/*
 * This file is part of jboss-admin-rest
 * Copyright 2009, Christos Vasilakis (cvasilak@gmail.com)
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.jboss.admin.rest.domain.deployments;

import org.jboss.admin.rest.domain.ComponentsContainer;
import org.jboss.admin.rest.domain.common.ManagedPropertyBean;
import org.jboss.admin.rest.exceptions.InternalServerErrorException;
import org.jboss.admin.rest.factory.ProfileServiceFactory;
import org.jboss.admin.rest.util.ManagedComponentUtils;
import org.jboss.deployers.spi.management.ManagementView;
import org.jboss.managed.api.ComponentType;
import org.jboss.managed.api.DeploymentState;
import org.jboss.managed.api.ManagedComponent;
import org.jboss.managed.api.ManagedDeployment;

import javax.xml.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author cvasilak
 */
@XmlRootElement(name = "war")
@XmlType(propOrder = {"name", "simpleName", "type", "status", "contextRoot", "servlets", "configuration", "statistics", "url"})
@XmlAccessorType(XmlAccessType.NONE)
public class ManagedDeploymentWarBean extends ManagedDeploymentBean {

	/* WebApplication Properties
	 * (disclaimer: statistic descriptions were retrieved from embjopr web app)
	 */
	enum WebAppProperty {
		START_TIME("startTime", "the start time of the WAR"),
		CONFIG_FILE("configFile", "the config file used"),
		DEPLOYMENT_DESCRIPTOR("deploymentDescriptor", "the deployment descriptor of this WAR"),
		DOCBASE("docBase", "the document root base"),
		ANTIJARLOCKING("antiJARLocking", "antiJARLocking property"),
		ANTIRESOURCELOCKING("antiResourceLocking", "antiResourceLocking property");
		
		private final String name;
		private final String descr;

		private WebAppProperty(String name, String descr) {
			this.name = name;
			this.descr = descr;
		}

		public String getName() {
			return name;
		}

		public String getDescription() {
			return descr;
		}
	}

	/* WebApplicationManager Statistics
	 * (disclaimer: statistic descriptions were retrieved from embjopr web app)
	 */
	enum WebAppMgrStatistic {
		ACTIVE_SESSIONS("activeSessions", "the number of sessions that are currently active for this WAR"),
		MAX_ACTIVE_SESSIONS("maxActive", "the maximum number of sessions that have been active for this WAR"),
		CREATED_SESSIONS("sessionCounter", "the number of sessions created for this WAR"),
		EXPIRED_SESSIONS("expiredSessions", "the number of expired sessions for this WAR"),
		REJECTED_SESSIONS("rejectedSessions", "the number of sessions rejected for this WAR"),
		AVG_SESSION_ALIVE("sessionAverageAliveTime", "the average alive time of sessions for this WAR"),
		MAX_SESSION_ALIVE("sessionMaxAliveTime", "the maximum alive time of sessions for this WAR");

		private final String name;
		private final String descr;

		private WebAppMgrStatistic(String name, String descr) {
			this.name = name;
			this.descr = descr;
		}

		public String getName() {
			return name;
		}

		public String getDescription() {
			return descr;
		}
	}

	/* aggregated Servlet Statistics
	 * (disclaimer: statistic descriptions were retrieved from embjopr web app)
	 */
	enum ServletStatistic {
		MIN_RESPONSE_TIME("minTime", "the minimum response time for requests serviced by this WAR"),
		AVG_RESPONSE_TIME("processingTime", "the average response time for requests serviced by this WAR"),
		MAX_RESPONSE_TIME("maxTime", "the maximum response time for requests serviced by this WAR"),
		TOTAL_RESPONSE_TIME("processingTime", "the total response time for requests serviced by this WAR"),
		REQUESTS_SERVED("requestCount", "the number of requests serviced by this WAR"),
		ERROR_COUNT("errorCount", "the number of error responses sent by this WAR");
		
		private final String name;
		private final String descr;

		private ServletStatistic(String name, String descr) {
			this.name = name;
			this.descr = descr;
		}

		public String getName() {
			return name;
		}

		public String getDescription() {
			return descr;
		}
	}

	public ManagedDeploymentWarBean() {
	}

	public ManagedDeploymentWarBean(ManagedDeployment deployment) {
		super(deployment);
	}

	@XmlElement(name = "contextRoot")
	public String getContextRoot() {
		String cRoot;

		if (deployment.getDeploymentState() == DeploymentState.STARTED) {
			cRoot = ManagedComponentUtils.getProperty(deployment.getProperty("contextRoot"));
		} else {
			cRoot = "";
		}

		return cRoot;
	}


	@XmlElement(name = "servlets-jsp")
	public ComponentsContainer getServlets() throws InternalServerErrorException, Exception {
		ComponentsContainer container = new ComponentsContainer();

		if (deployment.getDeploymentState() == DeploymentState.STARTED) {
			ManagementView mv = ProfileServiceFactory.getCurrentManagementView();

			// retrieve servlets
			String regex = "jboss.web:J2EEApplication=none,J2EEServer=none,WebModule=//localhost" + getContextRoot() + ",j2eeType=Servlet,name=(?!(default))\\w+";

			Set<ManagedComponent> servlets = mv.getComponentsForType(new ComponentType("MBean", "Servlet"));

			Pattern pattern = Pattern.compile(regex);

			for (ManagedComponent servlet : servlets) {
				Matcher matcher = pattern.matcher(servlet.getName());

				if (matcher.matches()) {
					container.add(servlet);
				}
			}
		}

		return container;
	}

	@XmlElementWrapper(name = "configuration")
	@XmlElement(name = "property")
	public List<ManagedPropertyBean> getConfiguration() throws InternalServerErrorException, Exception {
		List<ManagedPropertyBean> properties = new ArrayList<ManagedPropertyBean>();

		if (deployment.getDeploymentState() == DeploymentState.STARTED) {
			ManagementView mv = ProfileServiceFactory.getCurrentManagementView();

			// retrieve WebApplication properties
			ManagedComponent webApp = mv.getComponent("jboss.web:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost" + getContextRoot(), new ComponentType("MBean", "WebApplication"));

			for (WebAppProperty property : WebAppProperty.values()) {
				properties.add(new ManagedPropertyBean(webApp.getProperty(property.getName()), property.getDescription()));
			}
		}
	
		return properties;
	}
	
	@XmlElementWrapper(name = "statistics")
	@XmlElement(name = "statistic")
	public List<ManagedPropertyBean> getStatistics() throws InternalServerErrorException, Exception {
		List<ManagedPropertyBean> statistics = new ArrayList<ManagedPropertyBean>();

		if (deployment.getDeploymentState() == DeploymentState.STARTED) {
			ManagementView mv = ProfileServiceFactory.getCurrentManagementView();

			// retrieve WebApplicationManager statistics
			ManagedComponent webAppManager = mv.getComponent("jboss.web:host=localhost,path=" + getContextRoot() + ",type=Manager", new ComponentType("MBean", "WebApplicationManager"));

			for (WebAppMgrStatistic statistic : WebAppMgrStatistic.values()) {
				statistics.add(new ManagedPropertyBean(webAppManager.getProperty(statistic.getName()), statistic.getDescription()));
			}

			// retrieve servlet statistics
			// the regex used for web app servlets match
			String regex = "jboss.web:J2EEApplication=none,J2EEServer=none,WebModule=//localhost" + getContextRoot() + ",j2eeType=Servlet,name=[^,]+";

			Set<ManagedComponent> servlets = mv.getComponentsForType(new ComponentType("MBean", "Servlet"));

			/* logic retrieved by the jboss-as-5 jopr plugin
			 * in particular "WebApplicationContextComponent.java" in org.rhq.plugins.jbossas5
			 */
			long min = Long.MAX_VALUE;
			long max = 0;
			long processingTime = 0;
			long avgProcessingTime = 0;
			int requestCount = 0;
			int errorCount = 0;

			Pattern pattern = Pattern.compile(regex);

			for (ManagedComponent servlet : servlets) {
				Matcher matcher = pattern.matcher(servlet.getName());

				if (matcher.matches()) {
					for (ServletStatistic statistic : ServletStatistic.values()) {
						if (statistic == ServletStatistic.MIN_RESPONSE_TIME) {
							Long longValue = (Long) ManagedComponentUtils.getSimplePropertyValue(servlet, statistic.getName());
							if (longValue < min)
								min = longValue;
						} else if (statistic == ServletStatistic.MAX_RESPONSE_TIME) {
							Long longValue = (Long) ManagedComponentUtils.getSimplePropertyValue(servlet, statistic.getName());
							if (longValue > max)
								max = longValue;
						} else if (statistic == ServletStatistic.AVG_RESPONSE_TIME) {
							Long longValue = (Long) ManagedComponentUtils.getSimplePropertyValue(servlet, statistic.getName());
							avgProcessingTime += longValue;
						} else if (statistic == ServletStatistic.TOTAL_RESPONSE_TIME) {
							Long longValue = (Long) ManagedComponentUtils.getSimplePropertyValue(servlet, statistic.getName());
							processingTime += longValue;
						} else if (statistic == ServletStatistic.REQUESTS_SERVED) {
							Integer intValue = (Integer) ManagedComponentUtils.getSimplePropertyValue(servlet, statistic.getName());
							requestCount += intValue;
						} else if (statistic == ServletStatistic.ERROR_COUNT) {
							Integer intValue = (Integer) ManagedComponentUtils.getSimplePropertyValue(servlet, statistic.getName());
							errorCount += intValue;
						}
					}
				}
			}

			for (ServletStatistic statistic : ServletStatistic.values()) {
				ManagedPropertyBean property = null;
				Double result;

				if (statistic == ServletStatistic.MIN_RESPONSE_TIME) {
					result = (min != Long.MAX_VALUE) ? (double)min : Double.NaN;
					property = new ManagedPropertyBean(statistic.getName(), String.valueOf(result), statistic.getDescription());
				} else if (statistic == ServletStatistic.MAX_RESPONSE_TIME) {
					result = (max != 0) ? (double)max : Double.NaN;
					property = new ManagedPropertyBean(statistic.getName(), String.valueOf(result), statistic.getDescription());
				} else if (statistic == ServletStatistic.AVG_RESPONSE_TIME) {
					result = (requestCount > 0) ? ((double)avgProcessingTime / (double)requestCount) : Double.NaN;
					property = new ManagedPropertyBean("averageResponseTime" /* use a friendly name to avoid conflict("processingTime") confusion */, String.valueOf(result), statistic.getDescription());
				} else if (statistic == ServletStatistic.TOTAL_RESPONSE_TIME) {
					result = (double)processingTime;
					property = new ManagedPropertyBean(statistic.getName(), String.valueOf(result), statistic.getDescription());
				} else if (statistic == ServletStatistic.REQUESTS_SERVED) {
					property = new ManagedPropertyBean(statistic.getName(), String.valueOf((int)requestCount), statistic.getDescription());
				} else if (statistic == ServletStatistic.ERROR_COUNT) {
					property = new ManagedPropertyBean(statistic.getName(), String.valueOf((int)errorCount), statistic.getDescription());
				}

				statistics.add(property);
			}
		}

		return statistics;
	}
}
